package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.QuestionFormDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.QuestionAdminPageQuery;
import com.tianji.learning.domain.query.QuestionPageQuery;
import com.tianji.learning.domain.vo.QuestionAdminVO;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author xjs
 */
@Service
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {


    @Autowired
    private UserClient userClient;

    @Autowired
    @Lazy
    private InteractionReplyServiceImpl replyService;

    @Autowired
    private SearchClient searchClient;

    @Autowired
    private CourseClient courseClient;

    @Autowired
    private CatalogueClient catalogueClient;

    @Autowired
    private CategoryCache categoryCache;

    @Override
    public void saveQuestion(QuestionFormDTO dto) {
        // dto -> po
        InteractionQuestion question = BeanUtils.copyBean(dto, InteractionQuestion.class);
        // fill userId
        question.setUserId(UserContext.getUser());
        // save
        this.save(question);
    }

    @Override
    public PageDTO<QuestionVO> queryQuestionPage(QuestionPageQuery dto) {
        Long userId = UserContext.getUser();
        // 设置查询条件
        LambdaQueryWrapper<InteractionQuestion> queryWrapper = setQueryWrapper(userId, dto);
        // 设置分页条件
        Page<InteractionQuestion> ipage = new Page(dto.getPageNo(), dto.getPageSize());
        // 分页查询
        List<InteractionQuestion> questions = this.page(ipage, queryWrapper).getRecords();
        if(CollUtils.isEmpty(questions)){
            return PageDTO.empty(ipage);
        }
        // 根据question中的latest_reply_id查询reply
        Map<Long, InteractionReply> replyMap = queryReplyMap(questions);
        // 根据question中的userId和reply中的userId查询user数据
        Map<Long, UserDTO> userMap = buildUserMap(questions, replyMap);
        // 构造返回的volist
        List<QuestionVO> voList = new ArrayList<>(questions.size());
        for (InteractionQuestion question : questions) {
            //把po对象转化成页面需要的vo
            QuestionVO vo = poToVo(question, userMap, replyMap);
            voList.add(vo);
        }
        return PageDTO.of(ipage, voList);
    }

    @Override
    public QuestionVO queryQuestionById(Long id) {
        // 根据id查询
        InteractionQuestion question = this.getById(id);
        if(question == null){
            throw new BizIllegalException("根据id查询问题为空:" + id);
        }
        // 查询user
        Map<Long, UserDTO> userMap = buildUserMap(Arrays.asList(question));
        // 填充vo
        return poToVo(question, userMap);
    }

    @Override
    public PageDTO<QuestionAdminVO> queryQuestionPageAdmin(QuestionAdminPageQuery query) {
        // 根据course名称查询courseId
        List<Long> courseIds = courseNameToCourseIds(query.getCourseName());
        // 设置查询条件
        LambdaQueryWrapper<InteractionQuestion> queryWrapper = setAdminQueryWrapper(query, courseIds);
        // 设置分页条件
        Page<InteractionQuestion> ipage = new Page<>(query.getPageNo(), query.getPageSize());
        // 分页查询question
        List<InteractionQuestion> questions = this.page(ipage, queryWrapper).getRecords();
        if(CollUtils.isEmpty(questions)){
            return PageDTO.empty(ipage);
        }
        // 构造question用户id列表
        List<Long> questionUserIds = getQuestionUserIds(questions, true);
        // 根据userId查询user信息
        Map<Long, UserDTO> userMap = queryUserMap(questionUserIds);
        // 查询courseMap
        Map<Long, CourseSimpleInfoDTO> courseMap = queryCourseMap(questions);
        // 查询catalogMap
        Map<Long, CataSimpleInfoDTO> catalogMap = queryCatalogueMap(questions);
        // 封装返回的结果列表
        List<QuestionAdminVO> list = new ArrayList<>(questions.size());
        for (InteractionQuestion question : questions) {
            // po -> vo
            QuestionAdminVO adminVo = poToAdminVo(question, userMap, courseMap, catalogMap);
            list.add(adminVo);
        }
        return PageDTO.of(ipage, list);
    }

    private List<Long> courseNameToCourseIds(String courseName){
        if(StringUtils.isEmpty(courseName)){
            return null;
        }
        // 根据course名称查询courseId
        return searchClient.queryCoursesIdByName(courseName);
    }

    private QuestionAdminVO poToAdminVo(InteractionQuestion question,
                                        Map<Long, UserDTO> userMap,
                                        Map<Long, CourseSimpleInfoDTO> courseMap,
                                        Map<Long, CataSimpleInfoDTO> catalogMap){
        QuestionAdminVO vo = BeanUtils.copyBean(question, QuestionAdminVO.class);
        // 填充用户
        UserDTO user = userMap.get(question.getUserId());
        if(user == null){
            throw new BizIllegalException("用户为空:"+question.getUserId());
        }
        vo.setUserName(user==null?"":user.getName());
        // 填充course
        CourseSimpleInfoDTO course = courseMap.get(question.getCourseId());
        if(course == null){
            throw new BizIllegalException("课程为空");
        }
        vo.setCourseName(course.getName());
        // 填充chapter section
        CataSimpleInfoDTO chapter = catalogMap.get(question.getChapterId());
        CataSimpleInfoDTO section = catalogMap.get(question.getSectionId());
        if(chapter == null){
            throw new BizIllegalException("章为空");
        }
        if(section == null){
            throw new BizIllegalException("节为空");
        }
        vo.setChapterName(chapter.getName());
        vo.setSectionName(section.getName());
        // 填充category
        String categoryNames = categoryCache.getCategoryNames(course.getCategoryIds());
        vo.setCategoryName(categoryNames);
        return vo;
    }

    private Map<Long, CataSimpleInfoDTO> queryCatalogueMap(List<InteractionQuestion> questions){
        Set<Long> catalogIds = new HashSet<>();
        questions.stream().forEach(q->{
            catalogIds.add(q.getChapterId());
            catalogIds.add(q.getSectionId());
        });
        List<CataSimpleInfoDTO> catalogueList = catalogueClient.batchQueryCatalogue(catalogIds);
        if(CollUtils.isEmpty(catalogueList)){
            throw  new BizIllegalException("查询不到章节信息:" + catalogIds);
        }
        return catalogueList.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, c -> c));
    }

    private Map<Long, CourseSimpleInfoDTO> queryCourseMap(List<InteractionQuestion> questions){
        List<Long> courseIds = questions.stream().map(InteractionQuestion::getCourseId).distinct().collect(Collectors.toList());
        List<CourseSimpleInfoDTO> courseList = courseClient.getSimpleInfoList(courseIds);
        if(CollUtils.isEmpty(courseList)){
            throw  new BizIllegalException("查询不到课程信息:" + courseIds);
        }
        return courseList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
    }

    private LambdaQueryWrapper<InteractionQuestion> setAdminQueryWrapper(QuestionAdminPageQuery query, List<Long> courseIds){
        LambdaQueryWrapper<InteractionQuestion> queryWrapper = new LambdaQueryWrapper<InteractionQuestion>();
        queryWrapper.in(CollUtils.isNotEmpty(courseIds), InteractionQuestion::getCourseId, courseIds);
        queryWrapper.eq(query.getStatus()!=null, InteractionQuestion::getStatus, query.getStatus());
        queryWrapper.ge(query.getBeginTime()!=null,InteractionQuestion::getCreateTime, query.getBeginTime());
        queryWrapper.le(query.getEndTime()!=null,InteractionQuestion::getCreateTime, query.getEndTime());
        return queryWrapper;
    }

    private LambdaQueryWrapper<InteractionQuestion> setQueryWrapper(Long userId, QuestionPageQuery dto){
        // 设置查询条件，隐含条件：管理员是否隐藏
        LambdaQueryWrapper<InteractionQuestion> queryWrapper = new LambdaQueryWrapper<InteractionQuestion>();
        queryWrapper.eq(InteractionQuestion::getCourseId, dto.getCourseId());
        queryWrapper.eq(dto.getSectionId()!=null, InteractionQuestion::getSectionId, dto.getSectionId());
        queryWrapper.eq(dto.getOnlyMine()!=null && dto.getOnlyMine(), InteractionQuestion::getUserId, userId);
        // 是否被管理员隐藏
        queryWrapper.eq(InteractionQuestion::getHidden, false);
        return queryWrapper;
    }

    private Map<Long, InteractionReply> queryReplyMap(List<InteractionQuestion> records){
        //构造reply id列表 查询reply信息
        List<Long> replyIds = records.stream()
                .filter(r -> r.getLatestAnswerId() != null && r.getLatestAnswerId() > 0)
                .map(InteractionQuestion::getLatestAnswerId)
                .distinct()
                .collect(Collectors.toList());
        if(CollUtils.isEmpty(replyIds)){
            return null;
        }
        List<InteractionReply> replies = replyService.listByIds(replyIds);
        if(CollUtils.isEmpty(replies)){
            throw new BizIllegalException("查询不到回复信息:" + replyIds);
        }
        return replies.stream().collect(Collectors.toMap(InteractionReply::getId, r -> r));
    }

    private Map<Long, UserDTO> buildUserMap(List<InteractionQuestion> questions){
        // 构造question用户id列表
        List<Long> questionUserIds = getQuestionUserIds(questions, false);
        // 根据userId查询user信息
        return queryUserMap(questionUserIds);
    }

    private Map<Long, UserDTO> buildUserMap(List<InteractionQuestion> questions, Map<Long, InteractionReply> replyMap){
        // 从rely中拿到所有的replyUserId，因为页面要展示replyUserName
        List<Long> replyUserIds = getReplyUserIds(replyMap, false);
        // 构造question用户id列表
        List<Long> questionUserIds = getQuestionUserIds(questions, false);
        // 合并questionUserId和replyUserId
        List<Long> totalUserIds = combine(questionUserIds, replyUserIds);
        // 根据userId查询user信息
        return queryUserMap(totalUserIds);
    }

    private List<Long> getReplyUserIds(Map<Long, InteractionReply> replyMap, boolean includeAnonymity){
        // 从rely中拿到所有的replyUserId，因为页面要展示replyUserName
        if(CollUtils.isEmpty(replyMap)) {
            return null;
        }
        return replyMap.values().stream()
                .filter(r->{
                    if(includeAnonymity){
                        return true;
                    }else{
                        return r.getAnonymity()!=null && !r.getAnonymity();
                    }
                })
                .map(InteractionReply::getUserId)
                .distinct()
                .collect(Collectors.toList());
    }

    private List<Long> getQuestionUserIds(List<InteractionQuestion> questions, boolean includeAnonymity){
        return questions.stream()
                .filter(r->{
                    if(includeAnonymity){
                        return true;
                    }else{
                        return r.getAnonymity() != null && !r.getAnonymity();
                    }
                })
                .map(InteractionQuestion::getUserId)
                .distinct()
                .collect(Collectors.toList());
    }

    private Map<Long, UserDTO> queryUserMap (List<Long> totalUserIds){
        if(CollUtils.isEmpty(totalUserIds)){
            return null;
        }
        //根据ids查询用户信息
        List<UserDTO> userList = userClient.queryUserByIds(totalUserIds);
        if(CollUtils.isEmpty(userList)){
            throw new BizIllegalException("查询不到用户信息:" + totalUserIds);
        }
        return userList.stream().collect(Collectors.toMap(UserDTO::getId, u -> u));
    }

    private QuestionVO poToVo(InteractionQuestion question, Map<Long, UserDTO> userMap){
        return poToVo(question, userMap, null, false);
    }

    private QuestionVO poToVo(InteractionQuestion question, Map<Long, UserDTO> userMap, Map<Long, InteractionReply> replyMap){
        return poToVo(question, userMap, replyMap, true);
    }

    private QuestionVO poToVo(InteractionQuestion question, Map<Long, UserDTO> userMap, Map<Long, InteractionReply> replyMap, boolean fillLatestReply){
        QuestionVO vo = BeanUtils.copyBean(question, QuestionVO.class);
        // 处理是否匿名提问
        Boolean anonymity = question.getAnonymity();
        // 匿名的不设置昵称
        if(anonymity != null && !anonymity){
            UserDTO userDTO = CollUtils.isEmpty(userMap)?null:userMap.get(question.getUserId());
            if(userDTO == null){
                throw new BizIllegalException("查询不到用户信息:" + question.getUserId());
            }
            vo.setUserName(userDTO.getName());
            vo.setUserIcon(userDTO.getIcon());
        }
        // 查询reply表->最新的回答信息
        Long latestAnswerId = question.getLatestAnswerId();
        if(fillLatestReply && latestAnswerId != null){
            InteractionReply reply = CollUtils.isEmpty(replyMap)?null:replyMap.get(latestAnswerId);
            if(reply == null){
                throw new BizIllegalException("查询不到回复信息:" + latestAnswerId);
            }
            // 设置最新的回复内容
            vo.setLatestReplyContent(reply.getContent());
            // 设置最新的回复的用户，匿名的不需要设置
            if(reply.getAnonymity()!=null && !reply.getAnonymity()){
                UserDTO userDTO = CollUtils.isEmpty(userMap)?null:userMap.get(reply.getUserId());
                if(userDTO == null){
                    throw new BizIllegalException("查询不到用户信息:" + question.getUserId());
                }
                vo.setLatestReplyUser(userDTO.getName());
            }else{
                vo.setLatestReplyUser("匿名用户");
            }
        }
        return vo;
    }

    private List<Long> combine(List<Long> userIds, List<Long> replyUserIds) {
        Set<Long> ids = new HashSet<>();
        if(CollUtils.isNotEmpty(userIds)){
            ids.addAll(userIds);
        }
        if(CollUtils.isNotEmpty(replyUserIds)){
            ids.addAll(replyUserIds);
        }
        return new ArrayList<>(ids);
    }
}
